#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <time.h>

#define QLEN 10

#ifndef HOST_NAME_MAX
#define  HOST_NAME_MAX 256
#endif

extern int initserver(int, const struct sockaddr *, socklen_t, int);

void serve(int sockfd) {
    int clfd;
    pid_t pid;
    set_cloexec(sockfd);
    struct timespec tv= {0, 100000000};
    for (;;) {
        if ((clfd= accept(sockfd, NULL, NULL)) < 0) {
            syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));
            exit(1);
        }
        if ((pid= fork()) < 0) {
            syslog(LOG_ERR, "ruptimed: fork error: %s", strerror(errno));
            exit(1);
        } else if (pid == 0) {
            char *tip= "ruptimed: start retrieve uptime result\n";
            if (dup2(clfd, STDOUT_FILENO) != STDOUT_FILENO ||
                dup2(clfd, STDERR_FILENO) != STDERR_FILENO) {
                syslog(LOG_ERR, "ruptimed: unexpected error");
                exit(1);
            }
            // 为了演示效果这里休眠 10
            write(clfd, tip, strlen(tip));
            sleep(10);
            //dont worry clfd = stdin as daemonize make it open to /dev/null
            close(clfd);
            execl("/usr/bin/uptime", "uptime", NULL);
            syslog(LOG_ERR, "ruptimed: unexpected return from exec: %s", strerror(errno));
            exit(1);

        } else {
            close(clfd);
            nanosleep(&tv, NULL);
            // waitpid(pid, &status, 0);
        }
    }
}

int main(int argc, char *argv[]) {
    struct addrinfo *aip, *ailist;
    struct addrinfo hint;
    int sockfd, err, n;
    char *host;

    if (argc != 1)
        err_quit("usage: ruptimed");
    if ((n= sysconf(_SC_HOST_NAME_MAX)) < 0)
        n= HOST_NAME_MAX;
    if ((host= malloc(n)) == NULL)
        err_sys("malloc error");
    if ((gethostname(host, n)) < 0)
        err_sys("gethostname error");
    daemonize("ruptimed");
    memset(&hint, 0, sizeof(hint));
    hint.ai_flags= AI_CANONNAME;
    hint.ai_socktype= SOCK_STREAM;
    hint.ai_addr= NULL;
    hint.ai_next= NULL;
    if ((err= getaddrinfo(host, "ruptime", &hint, &ailist)) != 0) {
        syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err));
        exit(1);
    }
    for (aip= ailist; aip != NULL; aip= ailist->ai_next) {
        if ((sockfd= initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0) {
            serve(sockfd);
            exit(0);
        }
    }
    exit(1);
}
